package com.kkom1.tapeat;

import java.util.ArrayList;

import android.R.interpolator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import data_management.PatternSet;
import data_management.PatternUnit;

public class RhythmPad extends RelativeLayout{
	private Context context = this.getContext();
	private Resources r = this.getResources();
	
	// User Interface
	private DrawingPad circle_inner = new DrawingPad(context); // Pad base, inner circle
	private DrawingPad circle_outer = new DrawingPad(context); // Pad base, outer circle
	private DrawingNeedle needle = new DrawingNeedle(context); // Pad second hand
	
	private void arrange_views(){
		this.addView(circle_outer);
		this.addView(circle_inner);
		this.addView(needle);
	}
	
	// Pad Animation and event
	private RotateAnimation needleAnim = null; // animation effect for second hand
	
	// Touch event
	private PadEvent padEvent = new PadEvent();			// event for pad
	
	// Pattern data management
	private PatternUnit patternWords = new PatternUnit(); // the pattern that is set by user
	private PatternSet tempSet = new PatternSet();
	public PatternSet getPatternSet() { 
		return tempSet; 
	}
	public PatternUnit getPattern()	{ 
		return patternWords;
	}
	
	// property - size of the pad
	private int duration = 5000;		// pattern time limit
	private int padSize = 200;			// pad size
	private int padHalfSize;
	void setSize(int size) {
		padSize = size;
		padHalfSize = size / 2;

		// initializing views' size
		lParams = new RelativeLayout.LayoutParams(padSize, padSize);
		init_sizes();
	}
	public RhythmPad setDuration(int duration) {
		this.duration = duration;
		return this;
	}
	
	// Image Resources
	private int res_inner;
	private int res_outer;
	private int res_pattern;
	private int res_needle;
	
	public RhythmPad setRes_Inner(int res){
		res_inner = res;
		
		// refreshing
	//	circle_inner.setBackground(r.getDrawable(res));
		circle_inner.setImageDrawable(r.getDrawable(res));
		circle_inner.invalidate();
		
		return this;
	}
	public RhythmPad setRes_Outer(int res){
		res_outer = res;
		
		// refreshing
		circle_outer.setImageDrawable(r.getDrawable(res));
		circle_outer.invalidate();
		
		return this;
	}
	public RhythmPad setRes_Pattern(int res){
		res_pattern = res;
		
		// refreshing
		refresh_shader_pattern();
		return this;
	}
	public RhythmPad setRes_Needle(int res){
		res_needle = res;
		return this;
	}

	// bitmaps 
	private Bitmap bmp_pattern;
	private BitmapShader shader_pattern;
	private void refresh_shader_pattern(){
		bmp_pattern = BitmapFactory.decodeResource(r, res_pattern);
		bmp_pattern = Bitmap.createScaledBitmap(bmp_pattern, padSize, padSize, true);
		shader_pattern = new BitmapShader(bmp_pattern, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
	}
	
	// Constructors
	public RhythmPad(Context context, int padSize, int duration){
		super(context);
		setSize(padSize);
		setDuration(duration);
		
		init();
	}
	
	public RhythmPad(Context context, int innerRes, int outerRes, int needleRes, int patternRes, int padSize, int duration) {
		this(context, padSize, duration);
		
		setRes_Inner(innerRes);
		setRes_Outer(outerRes);
		setRes_Needle(needleRes);
		setRes_Pattern(patternRes);
	}
	
	private LayoutParams lParams = new RelativeLayout.LayoutParams(padSize, padSize);
	private void init_sizes(){
		this.setLayoutParams(lParams);
		circle_inner.setLayoutParams(lParams);
		circle_outer.setLayoutParams(lParams);
		needle.setLayoutParams(lParams);
		needle.setSize(padSize);
	}

	// initializer
	private void init(){
		// setting View Size
		init_sizes();
		// adding views to layout
		arrange_views();
		// setting needle animation
		init_animation();
		circle_inner.setOnTouchListener(padEvent);
		// this setting is needed to recognize what the action
		setClickable(true);
		
		
		animHandler = new AnimHandler();		// handler setting
		tempSet.setPatternUnit(patternWords);
	}
	
	private void init_event(){
		
	}
	
	private void init_animation(){
		init_needle_animation();
	}
	
	// animation preparing
	private void init_needle_animation(){
		needleAnim = new RotateAnimation(0, 360, padHalfSize, padHalfSize);
		needleAnim.setInterpolator(context, interpolator.linear);
		needleAnim.setDuration(duration);
		needleAnim.setAnimationListener(padEvent);
	}
	
	// 占쌍니몌옙占싱션울옙 占쏙옙占쏙옙 占싱븝옙트 占쏙옙占쏙옙
	public void setOnEndListener(OnEventListener onEnd){
		padEvent.setOnEndListener(onEnd);
	}
	
	// 占싻듸옙占쏙옙 占쏙옙占�占쏙옙占쏙옙 占십깍옙화(占쏙옙占쏙옙占�占쏙옙占쏙옙占쏙옙 占쏙옙占쏙옙.)
	public void prepareNext(){
		patternWords = new PatternUnit();
		tempSet = new PatternSet(patternWords);
		for(; !patternGraphics.isEmpty(); ){
			patternGraphics.remove(0).setVisibility(INVISIBLE);
		}
		needleAnim.reset();
		init_animation();
	}
	
	public void reset(){
		prepareNext();
		for(; !patternGraphics.isEmpty(); ){
			patternGraphics.remove(0).setVisibility(INVISIBLE);
		}
		needleAnim.reset();
		init_animation();
		circle_inner.setPressed(false);
	}

	public void refresh(){
		refresh_shader_pattern();
	}
	
	////////////////////////////////////////////////////////////////////////////////////////////
	/////// graphic classes////////////////////////////////////////////////////////////////////
	
	// time needle
	private class DrawingNeedle extends View{
		private Context context;
		private float radius;
		private int res;
		private Paint paint = new Paint();
		public DrawingNeedle setSize(int size){
			radius = size/2;
			invalidate();
			return this;
		}
		public DrawingNeedle setRes(int res){
			this.res = res;
			return this;
		}
		public DrawingNeedle(Context context) {
			super(context);
			this.context = context;
			paint.setColor(Color.WHITE);
			paint.setStrokeWidth(9);
		}
		protected void onDraw(Canvas canvas){
			super.onDraw(canvas);
			canvas.drawLine(radius - 9/2, radius, radius - 9/2, 0, paint);
		}
	}
	
	class DrawingPad extends ImageView {
		public DrawingPad(Context context) {
			super(context);
			this.setAdjustViewBounds(true);
		}
	}
	
	// 占쏙옙占쏙옙占쏙옙 占쌓뤄옙占쌍댐옙 호
	class DrawingPattern extends View {
		private float stDegree, degree;
		private Paint paint = new Paint();
		private int size;
		private RectF rect;
		private BitmapShader bmpShader;
		public void setShader(BitmapShader shader){ 
			bmpShader = shader;
			paint.setShader(bmpShader);
		}
		public void setDegree(float degree) { this.degree = degree; }
		public DrawingPattern(Context context, BitmapShader bitmapShader, float stDegree, float degree, int size) {
			super(context);
			
			this.stDegree = stDegree;
			this.degree = degree;
			this.size = size;
			this.bmpShader = bitmapShader;
			
			init();
		}
		
		private void init(){
			rect = new RectF(0, 0, size, size);
			paint.setAntiAlias(true);
			setShader(bmpShader);
			
			// setting handler for redraw
			animHandler.sendEmptyMessageDelayed(0, resetTime);
		}
		
		protected void onDraw(Canvas canvas){
			super.onDraw(canvas);
			canvas.drawArc(rect, stDegree, degree, true, paint);
		}
	}
	
	/////// graphic classes////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////////////

	
	
	////////////////////////////////////////////////////////////////////////////////////////////
	/////// Event handling ///////////////////////////////////////////////////////////////////
	private ArrayList<DrawingPattern> patternGraphics = new ArrayList<DrawingPattern>();

	// 占싻드에 占쏙옙載�占쏙옙치 占싱븝옙트
	class PadEvent implements View.OnTouchListener, Animation.AnimationListener {
		private OnEventListener onEnd;
		private static final int STATE_IDLE = 0;
		private static final int STATE_INSERTION = 1;
		private static final int STATE_FINISH = 2;
		
		private int state = 0;
		
		protected void setOnEndListener(OnEventListener onEnd){
			this.onEnd = onEnd;
		}
		
		// 占싱븝옙트 占쏙옙체
		public boolean onTouch(View v, MotionEvent e) {
			int event = e.getActionMasked();
			long t = System.currentTimeMillis();
			
			switch(state){
			case STATE_IDLE:
				if(event == MotionEvent.ACTION_DOWN){
					action_down(t);
					circle_inner.setPressed(true);
					needle.startAnimation(needleAnim);
				}
				break;
			case STATE_INSERTION:
				switch(event){
				case MotionEvent.ACTION_DOWN:
					action_down(t);
					circle_inner.setPressed(true);
					break;
				case MotionEvent.ACTION_UP:
					action_up(t);
					circle_inner.setPressed(false);
					break;
					default: break;
				}
				break;
				
			case STATE_FINISH:
/*				if(focusedPattern !=null) action_up(t);
				state = STATE_IDLE;*/
				break;
				
			default: return false;
				
			}
			
			return true;
		}
		
		public void onAnimationRepeat(Animation animation) {
			Log.d("Needle Animation Repeat: ", "true");
		}
		public void onAnimationStart(Animation animation) {
			Log.d("Needle Animation Start: ", "true");
			state = STATE_INSERTION;
		}
		public void onAnimationEnd(Animation animation) {
			Log.d("Needle Animation End: ", "true");
			state = STATE_FINISH;
			long t = System.currentTimeMillis();
			state = STATE_IDLE;
			if(focusedPattern !=null) action_up(t);
			onEnd.go();
			reset();
		}
	}

	public interface OnEventListener {
		public void go();
	}
	
	// 占쏙옙占쏙옙 占쏙옙占�
	private float degreeOf(Long dTime, Long stTime) {
		return ((dTime - stTime) / (float) duration * 360.0f);
	}

	// 占싱븝옙트: 占쏙옙占쏙옙 占쏙옙 占쏙옙
	private void action_up(Long t) {
		// calculate degree
		Long prev_time = patternWords.get(patternWords.size() - 1);
		float degree = degreeOf(t, prev_time);

		// redraw
		focusedPattern.setDegree(degree);
		focusedPattern.invalidate();
		needle.bringToFront();
		
		// adding end of the pattern
		patternWords.add(t);

		// focused Pattern
		focusedPattern = null;
	}

	// 占싱븝옙트: 占쏙옙占쏙옙 占쏙옙 占쏙옙
	private void action_down(Long t) {
		// adding the starting of a pattern unit
		patternWords.add(t);

		// calculate degree
		float stDegree = degreeOf(t, patternWords.get(0)) - 90.0f;

		// drawing the pattern
		focusedPattern = new DrawingPattern(context, shader_pattern, stDegree, 0, padSize);

		// adding the graphic pattern
		patternGraphics.add(focusedPattern);
		addView(focusedPattern);

		// bring the inner circle to front
		needle.bringToFront();
	}

	// ///// Event handling
	// ///////////////////////////////////////////////////////////////////
	// //////////////////////////////////////////////////////////////////////////////////////////

	// ////////////// Handler Setting
	// ////////////////////////////////////////////////
	private DrawingPattern focusedPattern = null;
	private AnimHandler animHandler;
	
	private int resetTime = 5;

	// 占쏙옙占쏙옙 占시곤옙占쏙옙占쏙옙 redraw 占쏙옙 占싹깍옙 占쏙옙占쏙옙 占쌘들러. 처占쏙옙占쏙옙.
	class AnimHandler extends Handler {
		public void handleMessage(Message msg) {
			if (focusedPattern == null)
				return;

			long t = System.currentTimeMillis();
			// calculate degree
			float degree = degreeOf(t,
					patternWords.get(patternWords.size() - 1));

			// redraw
			focusedPattern.setDegree(degree);
			focusedPattern.invalidate();

			// bring inner circle to front
			// dl.bringToFront();
			sendEmptyMessageDelayed(0, resetTime);
		}
	}
}